package main

import (
	"bufio"
	"flag"
	"fmt"
	"io"
	"os"
	"strconv"
	"strings"

	"code.google.com/p/jnj/cmd/util"
)

const maxPrefix = 2 // most words to put in a prefix

var die = util.Die

var difficulty = flag.Int("difficulty", 1, "1 = easy, 2 = hard")

var (
	emvoweled map[string][]string // maps "wrd" -> ["word", "weird", "ward", ...]
	frequency map[string]int      // frequency that a (non-disemvoweled) word appears in training
	prefixes  map[string]*prefix  // stores prefix objects, retrievable by their space-separated words
)

type prefix struct {
	words    []string
	suffixes []suffix
}

func (p *prefix) String() string {
	return strings.Join(p.words, " ")
}

// popSuffix returns the most frequent suffix of p.
func (p *prefix) popSuffix() string {
	if len(p.suffixes) > 1 {
		fmt.Println("Options!", p.suffixes)
	}
	return p.suffixes[0].s
}

type suffix struct {
	s string // the suffix
	n int    // number of times this suffix has been found for it's prefix
}

func (s suffix) String() string {
	return s.s + "(" + strconv.Itoa(s.n) + ")"
}

func main() {
	flag.Parse()

	if len(flag.Args()) != 1 {
		fmt.Fprintln(os.Stderr, "Usage:", os.Args[0], "training_file")
		flag.Usage()
		os.Exit(1)
	}
	f, err := os.Open(flag.Arg(0))
	die(err)

	emvoweled = make(map[string][]string)
	frequency = make(map[string]int)
	prefixes = make(map[string]*prefix)
	populate(f) // set up our maps
	//for _, p := range prefixes {
	//	fmt.Println(p.String(), "->", p.suffixes)
	//}

	inputScanner := bufio.NewScanner(os.Stdin)
	inputScanner.Split(bufio.ScanWords)

	var translation = make([]string, 0)
	switch *difficulty {

	case 1:
		// easy

		for inputScanner.Scan() {
			wrd := inputScanner.Text()
			words := emvoweled[wrd]
			if len(words) > 0 {
				// there are matches, use the most frequent one
				var sfreq string
				var nfreq int
				for _, w := range words {
					if frequency[w] > nfreq {
						sfreq = w
						nfreq = frequency[w]
					}
				}
				translation = append(translation, sfreq)
			} else {
				// nothing, just use the wrd
				translation = append(translation, wrd)
			}
		}

	case 2:
		// hard

		for inputScanner.Scan() {
			wrd := inputScanner.Text()
			words := emvoweled[wrd]
			if len(words) == 0 {
				// nothing, just use the wrd
				translation = append(translation, wrd)
				continue
			}

			// look for the longest matching prefix between the training text
			// and the re-emvoweled translation we have so far such that
			// the prefix contains wrd as a disemvoweled suffix
			var pref *prefix
			var ok bool
			for i := 0; i < maxPrefix; i++ {
				if len(translation)-(1+i) < 0 {
					break
				}
				possible := strings.Join(translation[len(translation)-(1+i):], " ")
				if pref, ok = prefixes[possible]; !ok {
					break
				}
				for _, suff := range pref.suffixes {
					sff := disemvowel(suff.s)
					if sff == wrd {
						fmt.Println("hit")
						break
					}
				}
				pref = nil // no hits
			}

			if pref == nil {
				// no prefixes, just use the most frequent match
				var sfreq string
				var nfreq int
				for _, w := range words {
					if frequency[w] > nfreq {
						sfreq = w
						nfreq = frequency[w]
					}
				}
				translation = append(translation, sfreq)
				continue
			}

			// we have the best matching prefix from the training text.
			// output the most frequent suffix to that prefix.
			//fmt.Println(pref.String(), "->", pref.suffixes)
			translation = append(translation, pref.popSuffix())
		}
	}
	fmt.Println(strings.Join(translation, " "))
}

func disemvowel(s string) string {
	var out string
	for _, c := range s {
		if c == 'a' || c == 'e' || c == 'i' || c == 'o' || c == 'u' {
			continue
		}
		out += string(c)
	}
	return out
}

func populate(f io.Reader) {
	trainingScanner := bufio.NewScanner(f)
	trainingScanner.Split(bufio.ScanWords)

	prevWords := make([]string, maxPrefix)

	for trainingScanner.Scan() {
		word := trainingScanner.Text()
		word = strings.ToLower(word)
		word = strings.Trim(word, ",.!?-()\";:")
		if word == "" {
			continue
		}

		// populate prefixes map
		suff := suffix{s: word}
		for i := 0; i < maxPrefix; i++ {
			// we are at the start of the training text, there aren' enough
			// previous words yet to make a prefix this size.
			if prevWords[i] == "" {
				break
			}
			pref := prefix{words: prevWords[len(prevWords)-(1+i):]}
			if existingPref, ok := prefixes[pref.String()]; !ok {
				suff.n = 1
				pref.suffixes = []suffix{suff}
				prefixes[pref.String()] = &pref
			} else {
				for ii, existingSuff := range existingPref.suffixes {
					if existingSuff.s == suff.s {
						existingPref.suffixes[ii].n++
						goto doneThisPrefix
					}
				}
				suff.n = 1
				existingPref.suffixes = append(existingPref.suffixes, suff)
			}
		doneThisPrefix:
		}
		prevWords = append(prevWords[1:], word)

		// populate frequency map
		frequency[word]++

		// populate emvoweled map
		wrd := disemvowel(word)

		if words, ok := emvoweled[wrd]; ok {
			// case 1: this wrd already has words associated with it. add word
			// if it is not already in the list

			for _, w := range words {

				if word == w {
					goto doneemvoweled // continue on outer loop
				}
			}
			// not in the list; append
			emvoweled[wrd] = append(emvoweled[wrd], word)
		} else {

			// case 2: this wrd has no words; start a new list

			emvoweled[wrd] = []string{word}
		}
	doneemvoweled:
	}
}

func getPrefixes(s string) []string {
	return nil
}
